/*
左值的英文简写为“lvalue”，右值的英文简写为“rvalue”。很多人认为它们分别是"left value"、"right value" 的缩写，其实不然。

lvalue 是“loactor value”的缩写，可意为存储在内存中、有明确存储地址（可寻址）的数据，
而 rvalue 译为 "read value"，指的是那些可以提供数据值的数据（不一定可以寻址，例如存储于寄存器中的数据）。

在c++11中，因为增加了右值引用(rvalue reference)的概念，所以c++98中的引用都称为了左值引用(lvalue reference)。
*/

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
namespace ReadValue {

    class MyString
    {
    public:
        static size_t CopyConstructionCount; //统计调用拷贝构造函数的次数
        static size_t MoveConstructionCount; //统计调用移动构造函数的次数
        static size_t CopyAsignCount; //统计调用拷贝赋值函数的次数
        static size_t MoveAsignCount; //统计调用移动赋值函数的次数

    public:
        // 构造函数
        MyString(const char* cstr = 0) {
            if (cstr) {
                m_data = new char[strlen(cstr) + 1];
                strcpy(m_data, cstr);
            }
            else {
                m_data = new char[1];
                *m_data = '\0';
            }
        }

        // 拷贝构造函数
        MyString(const MyString& str) {
            CopyConstructionCount++;
            m_data = new char[strlen(str.m_data) + 1];
            strcpy(m_data, str.m_data);
        }
        // 移动构造函数
        MyString(MyString&& str) noexcept
            :m_data(str.m_data) {
            MoveConstructionCount++;
            str.m_data = nullptr; //不再指向之前的资源了
        }

        // 拷贝赋值函数 =号重载
        MyString& operator=(const MyString& str) {
            CopyAsignCount++;
            if (this == &str) // 避免自我赋值!!
                return *this;

            delete[] m_data;
            m_data = new char[strlen(str.m_data) + 1];
            strcpy(m_data, str.m_data);
            return *this;
        }

        // 移动赋值函数 =号重载
        MyString& operator=(MyString&& str) noexcept {
            MoveAsignCount++;
            if (this == &str) // 避免自我赋值!!
                return *this;

            delete[] m_data;
            m_data = str.m_data;
            str.m_data = nullptr; //不再指向之前的资源了
            return *this;
        }

        ~MyString() {
            delete[] m_data;
        }

        char* get_c_str() const { return m_data; }
    private:
        char* m_data;
    };

    size_t MyString::CopyConstructionCount = 0;
    size_t MyString::MoveConstructionCount = 0;
    size_t MyString::CopyAsignCount = 0;
    size_t MyString::MoveAsignCount = 0;

    int main()
    {
        {
            int a1 = 10;
            int& refA = a1; // refA是a的别名， 修改refA就是修改a, a是左值，左移是左值引用

            //int& b = 1; //编译错误! 1是右值，不能够使用左值引用
            int&& a2 = 1; //实质上就是将不具名(匿名)变量取了个别名
            int b2 = 1;
    //        int&& c2 = b2; //编译错误！ 不能将一个左值复制给一个右值引用

            auto func= []{int i = 10; return i; };   
            int&& a3 = func();//返回值是右值（临时变量）

            const int& a4 = 1; //常量左值引用绑定 右值， 不会报错
            const int& a5 = func(); // 不会报错
        }


        vector<MyString> vecStr;
        vecStr.reserve(1000); //先分配好1000个空间
        for (int i = 0; i < 1000; i++) {
            vecStr.push_back(MyString("hello"));
        }
        cout << "\n\nvecStr.push_back(MyString('hello'))\n";
        cout << "\tCopyConstructionCount = " << MyString::CopyConstructionCount << endl;
        cout << "\tMoveConstructionCount = " << MyString::MoveConstructionCount << endl;
        cout << "\tCopyAsignCount = " << MyString::CopyAsignCount << endl;
        cout << "\tMoveAsignCount = " << MyString::MoveAsignCount << endl;

        {
            vector<MyString> vecStr;
            vecStr.reserve(1000); //先分配好1000个空间
            for (int i = 0; i < 1000; i++) {
                MyString tmp("hello");
                vecStr.push_back(tmp); //调用的是拷贝构造函数
            }
            cout << "\n\nMyString tmp   vecStr.push_back(tmp)\n";
            cout << "\n\n";
            cout << "\tCopyConstructionCount = " << MyString::CopyConstructionCount << endl;
            cout << "\tMoveConstructionCount = " << MyString::MoveConstructionCount << endl;
            cout << "\tCopyAsignCount = " << MyString::CopyAsignCount << endl;
            cout << "\tMoveAsignCount = " << MyString::MoveAsignCount << endl;

            cout << "\n\n";
            MyString::CopyConstructionCount = 0;
            MyString::MoveConstructionCount = 0;
            MyString::CopyAsignCount = 0;
            MyString::MoveAsignCount = 0;
            vector<MyString> vecStr2;
            vecStr2.reserve(1000); //先分配好1000个空间
            for (int i = 0; i < 1000; i++) {
                MyString tmp("hello");
                vecStr2.push_back(std::move(tmp)); //调用的是移动构造函数
            }
            cout << "\n\nMyString tmp   vecStr2.push_back(std::move(tmp));\n";
            cout << "\tCopyConstructionCount = " << MyString::CopyConstructionCount << endl;
            cout << "\tMoveConstructionCount = " << MyString::MoveConstructionCount << endl;
            cout << "\tCopyAsignCount = " << MyString::CopyAsignCount << endl;
            cout << "\tMoveAsignCount = " << MyString::MoveAsignCount << endl;
        }

        {
            MyString str1("hello"); //调用构造函数
            MyString str2("world"); //调用构造函数
            MyString str3(str1); //调用拷贝构造函数
            MyString str4(std::move(str1)); // 调用移动构造函数、
            //    cout << str1.get_c_str() << endl; // 此时str1的内部指针已经失效了！不要使用
            //注意：虽然str1中的m_dat已经称为了空，但是str1这个对象还活着，知道出了它的作用域才会析构！而不是move完了立刻析构
            MyString str5;
            str5 = str2; //调用拷贝赋值函数
            MyString str6;
            str6 = std::move(str2); // str2的内容也失效了，不要再使用
            /*
            str6 = std::move(str2)，虽然将str2的资源给了str6，但是str2并没有立刻析构，只有在str2离开了自己的作用域的时候才会析构，
            所以，如果继续使用str2的m_data变量，可能会发生意想不到的错误。

                    如果我们没有提供移动构造函数，只提供了拷贝构造函数，std::move()会失效但是不会发生错误，
                    因为编译器找不到移动构造函数就去寻找拷贝构造函数，也这是拷贝构造函数的参数是const T&常量左值引用的原因！

            c++11中的所有容器都实现了move语义，move只是转移了资源的控制权，本质上是将左值强制转化为右值使用，
            以用于移动拷贝或赋值，避免对含有资源的对象发生无谓的拷贝。
            move对于拥有如内存、文件句柄等资源的成员的对象有效，
            如果是一些基本类型，如int和char[10]数组等，
            如果使用move，仍会发生拷贝（因为没有对应的移动构造函数），所以说move对含有资源的对象说更有意义。


            */

        }
        return 0;
    }

   
}

